# Author: Chris Cartland
# Date: November 29, 2011
# Purpose: Playing around with a simple chessboard.

import re, sys

DEBUGGING_FLAGS = {'t' : False, 'print_legal_moves' : False, 'play_hvh' : False}
COMMAND = { 'list_moves' : 'show' }
DEBUG_STATE = {}
TEAM_WHITE = 'WHITE TEAM'
TEAM_BLACK = 'BLACK TEAM'
CHECKMATE = 'CHECKMATE'
PLAYING = 'PLAYING'
RESIGNED = 'RESIGNED'
DRAW = 'DRAW'
BLACK_ROOK = None
BLACK_KNIGHT = None
BLACK_BISHOP = None
BLACK_QUEEN = None
BLACK_KING = None
BLACK_PAWN = None
WHITE_ROOK = None
WHITE_KNIGHT = None
WHITE_BISHOP = None
WHITE_QUEEN = None
WHITE_KING = None
WHITE_PAWN = None
CAPTURE_PIECE = None

file_lookup = {'a':0, 'b':1, 'c':2, 'd':3, 'e':4, 'f':5, 'g':6, 'h':7}

def main():
  for arg in sys.argv[1:]:
    DEBUGGING_FLAGS[arg] = True
  initialize_pieces()
  if debug_on('t'):
    test_chessboard()
  b = Chessboard()
  if debug_on('play_hvh'):
    b.initialize_standard_board()
    play_board_until(b,'.')
    
  if debug_on('test_check'):
    b.initialize_blank()
    b.put_piece(WHITE_KING, Position('d4'))
    b.put_piece(BLACK_PAWN, Position('e4'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    copy = b.copy()
    mark_moves_as_captures(copy, legal_moves)
    print b.print_side(copy)
  
def play_board_until(board, end_string, turn=TEAM_WHITE):  
  while True:
    print
    print str(turn) + "'s turn."
    print 'Type "' + end_string + '" to quit.'
    if debug_on('print_legal_moves'):
      moves_board = board.copy()
      mark_moves_as_captures(moves_board, moves_board.get_legal_moves(turn))
      print board.print_side(moves_board)
    else:
      print board
    legal_moves = board.get_legal_moves(turn)
    if len(legal_moves) == 0:
      winning_team = TEAM_WHITE if turn == TEAM_BLACK else TEAM_BLACK
      print
      print
      print 'Checkmate!!!', winning_team, 'wins!'
      print
      print
      print board.get_piece(Position('f7')).move_history
      break
    else:
      print
      input = raw_input(turn + ' please enter next move:')
    if input == end_string:
      break
    elif input == COMMAND['list_moves']:
      print legal_moves
    else:
      try:
        move = Move(input)
        if move in legal_moves:
          board.force_move(move)
          print turn, 'moved', move      
          turn = (TEAM_WHITE if turn == TEAM_BLACK else TEAM_BLACK)
        else:
          print move, 'is not a legal move.'
          print 'Please enter one of the following legal moves:', legal_moves
      except InputException as e:
        print '"' + str(input) + '"', 'is not valid input.'
        print e
        print 'Please enter one of the following legal moves:', legal_moves
    
  
def mark_moves_as_captures(b, legal_moves):
  for move in legal_moves:
    b.put_piece(CAPTURE_PIECE, move.end_position)

def initialize_pieces():
  global BLACK_ROOK, BLACK_KNIGHT, BLACK_BISHOP, BLACK_QUEEN, BLACK_KING, BLACK_PAWN,\
WHITE_ROOK, WHITE_KNIGHT, WHITE_BISHOP, WHITE_QUEEN, WHITE_KING, WHITE_PAWN, CAPTURE_PIECE
  
  BLACK_ROOK = make_piece('r')
  BLACK_KNIGHT = make_piece('k')
  BLACK_BISHOP = make_piece('b')
  BLACK_QUEEN = make_piece('q')
  BLACK_KING = make_piece('w')
  BLACK_PAWN = make_piece('p')
  WHITE_ROOK = make_piece('R')
  WHITE_KNIGHT = make_piece('K')
  WHITE_BISHOP = make_piece('B')
  WHITE_QUEEN = make_piece('Q')
  WHITE_KING = make_piece('W')
  WHITE_PAWN = make_piece('P')
  CAPTURE_PIECE = make_piece('x')
  
  P = make_piece(WHITE_PAWN)

  file_lookup = {'a':0, 'b':1, 'c':2, 'd':3, 'e':4, 'f':5, 'g':6, 'h':7}

class Piece(str):
  def __init__(self, character):
    self.team = None
    self.name = character
    self.move_history = []
    if isinstance(character, Piece):
      self.team = character.team
      self.name = character.name
      self.move_history = list(character.move_history)
    elif character == 'x':
      self.team = None
    elif character.upper() == character:
      self.team = TEAM_WHITE
    else:
      self.team = TEAM_BLACK
    
  def add_move(self, move_number, move):
    self.move_history.append((move_number, move))
  
def make_piece(character):
  if character is None:
    return None
  return Piece(character)
  
class Position():
  def __init__(self, algebra):
    if type(algebra) == type(''):
      if re.match('[a-h][1-8]', algebra) is None:
        raise InputException('String is not a position "' + algebra + '"')
      file, rank = algebra[0], algebra[1]
      self.file = file_lookup[file]
      self.rank = int(rank) - 1
    else:
      #tuple
      try:
        self.file, self.rank = algebra
      except Exception:
        raise InputException('Object is not a position: ' + algebra)
  
  def __str__(self):
    return chr(self.file + 97) + str(self.rank + 1)
  
  def __repr__(self):
    return str(self)

  def __hash__(self):
    return str(self).__hash__()
  
  def __eq__(self, other):
    return str(self) == other

class InputException(Exception):
  def __str__(self):
    return 'InputException: ' + Exception.__str__(self)


  

class Move():
  def __init__(self, algebra, capture=False):
    if type(algebra) == type(''):
      if re.match('[a-h][1-8]x?[a-h][1-8]', algebra) is None:
        raise InputException('String is not a move "' + algebra + '"')
      self.capture = (algebra[2] == 'x')
      self.start_position = Position(algebra[:2])
      self.end_position = Position(algebra[-2:])
    else:
      #tuple
      self.capture = capture
      try:
        self.start_position, self.end_position = algebra
      except Exception:
        raise InputException('Object is not a move: ' + algebra)
  
  def reverse(self):
    return Move((self.end_position, self.start_position), capture=self.capture)

  def __repr__(self):
    return str(self)
    
  def __str__(self):
    return str(self.start_position) + ('x' if self.capture else '') + str(self.end_position)

  def __hash__(self):
    return str(self).__hash__()
  
  def __eq__(self, other):
    return str(self) == other

class Chessboard():
  def __init__(self):
    self.initialize_blank()
  
  def initialize_blank(self):
    self.board = []
    for x in xrange(8):
      self.board.append([])
      for y in xrange(8):
        self.board[x].append(None)

  def force_move(self, move, move_number=0):
    pos1 = move.start_position
    pos2 = move.end_position
    self.board[pos2.file][pos2.rank] = self.board[pos1.file][pos1.rank]
    if self.board[pos2.file][pos2.rank] is not None:
      self.board[pos2.file][pos2.rank].add_move(move_number, move)
    self.board[pos1.file][pos1.rank] = None
    
  def put_piece(self, piece, position):
    self.board[position.file][position.rank] = piece
  
  def get_piece(self, position):
    return self.board[position.file][position.rank]
  
  def copy(self):
    new_board = Chessboard()
    new_board.board = []
    for x in xrange(8):
      new_board.board.append([])
      for y in xrange(8):
        new_board.board[x].append(make_piece(self.board[x][y]))
    return new_board
  
  def get_legal_moves(self, team):
    legal_moves = []
    for file in xrange(8):
      for rank in xrange(8):
        position = Position((file,rank))
        piece = self.get_piece(position)
        if piece:
          if (piece == piece.upper() and team == TEAM_WHITE) \
              or (piece == piece.lower() and team == TEAM_BLACK):
            for move in self.get_legal_moves_from_position(position):
              legal_moves.append(move) 
    return legal_moves
    
  def get_legal_moves_from_position(self, position):
    file, rank = position.file, position.rank
    moving_piece = self.get_piece(position)
    if moving_piece is None:
      return []
    legal_moves = []
    if moving_piece == WHITE_PAWN:
      team = TEAM_WHITE
      for move in self.get_legal_moves_white_pawn(position):
        legal_moves.append(move)
    elif moving_piece == BLACK_PAWN:
      for move in self.get_legal_moves_black_pawn(position):
        legal_moves.append(move)
    elif moving_piece == WHITE_ROOK or moving_piece == BLACK_ROOK:
      for move in self.get_legal_moves_rook(position):
        legal_moves.append(move)
    elif moving_piece == WHITE_KNIGHT or moving_piece == BLACK_KNIGHT:
      for move in self.get_legal_moves_knight(position):
        legal_moves.append(move)
    elif moving_piece == WHITE_BISHOP or moving_piece == BLACK_BISHOP:
      for move in self.get_legal_moves_bishop(position):
        legal_moves.append(move)
    elif moving_piece == WHITE_QUEEN or moving_piece == BLACK_QUEEN:
      for move in self.get_legal_moves_queen(position):
        legal_moves.append(move)
    elif moving_piece == WHITE_KING or moving_piece == BLACK_KING:
      for move in self.get_legal_moves_king(position):
        legal_moves.append(move)
    moves_to_return = []
    for move in legal_moves:
      copy = self.copy()
      copy.force_move(move)
      positions_of_kings_in_check = copy.get_positions_of_kings_in_check()
      prohibit = False
      for pok in positions_of_kings_in_check:
        king_in_check = copy.get_piece(pok)
        assert king_in_check is not None, 'king is not None'
        if king_in_check.team == moving_piece.team:
          prohibit = True
      if prohibit:
        debug_print(move, 'prohibit_check', 'check_move')
      else:
        moves_to_return.append(move)

    return moves_to_return
    
  def get_legal_moves_white_pawn(self, position):
    file, rank = position.file, position.rank
    team = self.board[file][rank].team
    legal_moves = []
    if rank + 1 < 8:
      if self.board[file][rank + 1] is None:
        new_pos = Position((file, rank + 1))
        legal_moves.append(Move((position, new_pos)))
      if file > 0 and self.board[file - 1][rank + 1] is not None\
          and team != self.board[file - 1][rank + 1].team:
        new_pos = Position((file - 1, rank + 1))
        legal_moves.append(Move((position, new_pos), capture=True))
      if file < 7 and self.board[file + 1][rank + 1] is not None\
          and team != self.board[file + 1][rank + 1].team:
        new_pos = Position((file + 1, rank + 1))
        legal_moves.append(Move((position, new_pos), capture=True))
      if rank == 1 and \
          self.board[file][rank + 1] is None \
          and self.board[file][rank + 2] is None:
        new_pos = Position((file, rank + 2))
        legal_moves.append(Move((position, new_pos)))
    return legal_moves
  
  def get_legal_moves_black_pawn(self, position):
    file, rank = position.file, position.rank
    team = self.board[file][rank].team
    legal_moves = []
    if rank - 1 >= 0:
      if self.board[file][rank - 1] is None:
        new_pos = Position((file, rank - 1))
        legal_moves.append(Move((position, new_pos)))
      if file > 0 and self.board[file - 1][rank - 1] is not None\
          and team != self.board[file - 1][rank - 1].team:
        new_pos = Position((file - 1, rank - 1))
        legal_moves.append(Move((position, new_pos), capture=True))
      if file < 7 and self.board[file + 1][rank - 1] is not None\
          and team != self.board[file + 1][rank - 1].team:
        new_pos = Position((file + 1, rank - 1))
        legal_moves.append(Move((position, new_pos), capture=True))
      if rank == 6 and \
          self.board[file][rank - 1] is None \
          and self.board[file][rank - 2] is None:
        new_pos = Position((file, rank - 2))
        legal_moves.append(Move((position, new_pos)))
    return legal_moves
  
  def get_legal_moves_rook(self, position):
    file, rank = position.file, position.rank
    team = self.board[file][rank].team
    legal_moves = []
    f, r = file, rank
    while r > 0:
      r -= 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    f, r = file, rank
    while r < 7:
      r += 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    f, r = file, rank
    while f > 0:
      f -= 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    f, r = file, rank
    while f < 7:
      f += 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    return legal_moves
  
  def get_legal_moves_knight(self, position):
    file, rank = position.file, position.rank
    team = self.board[file][rank].team
    legal_moves = []
    difs = [(1,2), (2,1), (-1,2), (2,-1), (-2,1), (1, -2), (-1, -2), (-2, -1)]
    
    for df, dr in difs:
      f, r = file + df, rank + dr
      if f >= 0 and r >= 0 and f < 8 and r < 8:
        if self.board[f][r] is None:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos)))
        elif self.board[f][r].team != team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
    return legal_moves
    
  def get_legal_moves_bishop(self, position):
    file, rank = position.file, position.rank
    team = self.board[file][rank].team
    legal_moves = []
    f = file
    r = rank
    while r > 0 and f > 0:
      f -= 1
      r -= 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    f = file
    r = rank
    while r < 7 and f > 0:
      f -= 1
      r += 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    f = file
    r = rank
    while r > 0 and f < 7:
      f += 1
      r -= 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    f = file
    r = rank
    while r < 7 and f < 7:
      f += 1
      r += 1
      if self.board[f][r] is not None:
        if team != self.board[f][r].team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
        break
      new_pos = Position((f, r))
      legal_moves.append(Move((position, new_pos)))
    return legal_moves
  
  def get_legal_moves_queen(self, position):
    legal_moves = self.get_legal_moves_rook(position)
    for move in self.get_legal_moves_bishop(position):
      legal_moves.append(move)
    return legal_moves
  
  def get_legal_moves_king(self, position):
    file, rank = position.file, position.rank
    king = self.board[file][rank]
    team = king.team
    legal_moves = []
    difs = [(1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1,0)]
    
    for df, dr in difs:
      f, r = file + df, rank + dr
      if f >= 0 and r >= 0 and f < 8 and r < 8:
        if self.board[f][r] is None:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos)))
        elif self.board[f][r].team != team:
          new_pos = Position((f, r))
          legal_moves.append(Move((position, new_pos), capture=True))
    
    #castling
    if not self.king_is_in_check(position):
      if king.move_history == []:
        left_rook = self.get_piece(Position((0, rank)))
        correct_rook = WHITE_ROOK if team == TEAM_WHITE else BLACK_ROOK
        if left_rook == correct_rook and left_rook.move_history == []:
          positions = [Position((file, rank)), Position((file-1, rank)), \
                       Position((file-2, rank)), Position((file-3, rank))]
          if self.get_piece(positions[1]) is None \
              and self.get_piece(positions[2]) is None \
              and self.get_piece(positions[3]) is None:
            copy = self.copy()
            moves = [Move((positions[0], positions[1])), \
                     Move((positions[1], positions[2]))]
            king_not_in_check = True
            for move in moves:
              copy.force_move(move)
              if copy.king_is_in_check(move.end_position):
                king_not_in_check = False
            if king_not_in_check:
              legal_moves.append(Move((positions[0],positions[2])))
        right_rook = self.get_piece(Position((7, rank)))
        if right_rook == correct_rook and right_rook.move_history == []:
          positions = [Position((file, rank)), Position((file+1, rank)), \
                       Position((file+2, rank))]
          if self.get_piece(positions[1]) is None \
              and self.get_piece(positions[2]) is None:
            copy = self.copy()
            moves = [Move((positions[0], positions[1])), \
                     Move((positions[1], positions[2]))]
            king_not_in_check = True
            for move in moves:
              copy.force_move(move)
              if copy.king_is_in_check(move.end_position):
                king_not_in_check = False
            if king_not_in_check:
              legal_moves.append(Move((positions[0],positions[2])))
          
        # if king can make three sequential left moves without getting into check,
            # and the rook hasn't moved
          # then castling left is possible
        # if king can make two sequential right moves without getting into check,
            # and the rook hasn't moved
          # then castling right is possible
    return legal_moves


  def king_is_in_check(self, position, threat_team=None):
    file, rank = position.file, position.rank
    if threat_team is None:
      threat_team = TEAM_BLACK if self.board[file][rank].team == TEAM_WHITE else TEAM_WHITE
    def pawn():
      threat_piece = WHITE_PAWN if threat_team == TEAM_WHITE else BLACK_PAWN
      if threat_team == TEAM_WHITE:
        difs = [(1,-1), (-1,-1)]
      else:
        difs = [(1,1), (-1,1)]
      for df, dr in difs:
        f, r = file + df, rank + dr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] == threat_piece:
            return Position((f,r))
      return False
    def rook():
      threat_piece = WHITE_ROOK if threat_team == TEAM_WHITE else BLACK_ROOK
      for ctr in xrange(1,8):
        f, r = file, rank + ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      for ctr in xrange(1,8):
        f, r = file, rank - ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      for ctr in xrange(1,8):
        f, r = file + ctr, rank
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      for ctr in xrange(1,8):
        f, r = file - ctr, rank
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      return False
    def knight():
      threat_piece = WHITE_KNIGHT if threat_team == TEAM_WHITE else BLACK_KNIGHT
      difs = [(1,2), (2,1), (-1,2), (2,-1), (1,-2), (-2,1), (-1,-2), (-2,-1)]
      for df, dr in difs:
        f, r = file + df, rank + dr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] == threat_piece:
            return Position((f,r))
      return False
    def bishop():
      threat_piece = WHITE_BISHOP if threat_team == TEAM_WHITE else BLACK_BISHOP
      for ctr in xrange(1,8):
        f, r = file + ctr, rank + ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      for ctr in xrange(1,8):
        f, r = file - ctr, rank + ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      for ctr in xrange(1,8):
        f, r = file + ctr, rank - ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      for ctr in xrange(1,8):
        f, r = file - ctr, rank - ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      return False
    def queen():
      threat_piece = WHITE_QUEEN if threat_team == TEAM_WHITE else BLACK_QUEEN
      checked_locations = []
      #ROOK MOVES
      for ctr in xrange(1,8):
        f, r = file, rank + ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      for ctr in xrange(1,8):
        f, r = file, rank - ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      for ctr in xrange(1,8):
        f, r = file + ctr, rank
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      for ctr in xrange(1,8):
        f, r = file - ctr, rank
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
            if self.board[f][r] == threat_piece:
              debug_print(threat_piece, 'king_is_in_check rook', 'threat_piece')
              debug_print(threat_team, 'king_is_in_check rook', 'threat_team')
              return Position((f,r))
            else:
              break
      #BISHOP MOVES
      for ctr in xrange(1,8):
        f, r = file + ctr, rank + ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      for ctr in xrange(1,8):
        f, r = file - ctr, rank + ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      for ctr in xrange(1,8):
        f, r = file + ctr, rank - ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      for ctr in xrange(1,8):
        f, r = file - ctr, rank - ctr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] is not None:
              if self.board[f][r] == threat_piece:
                return Position((f,r))
              else:
                break
      if 'test_four_move_checkmate' in DEBUG_STATE \
          and DEBUG_STATE['test_four_move_checkmate']:
        print threat_piece, checked_locations
      return False

    def king():
      threat_piece = WHITE_KING if threat_team == TEAM_WHITE else BLACK_KING
      difs = [(1,1), (-1,1), (1,-1), (-1,-1), (0,1), (1,0), (0,-1), (-1,0)]
      for df, dr in difs:
        f, r = file + df, rank + dr
        if f >= 0 and r >= 0 and f < 8 and r < 8:
          if self.board[f][r] == threat_piece:
            return Position((f,r))
      return False
    
    return pawn() \
        or rook() \
        or knight() \
        or bishop() \
        or queen() \
        or king()
    
  def get_positions_of_kings_in_check(self):
    kings = []
    for file in xrange(8):
      for rank in xrange(8):
        position = Position((file, rank))
        piece = self.board[file][rank]
        if piece is not None:
          if piece == WHITE_KING or piece == BLACK_KING:
            if self.king_is_in_check(position):
              kings.append(position)
              if debug_on('pkic'):
                print piece, position, self.get_piece(position), self.king_is_in_check(position)
    return kings

  def initialize_standard_board(self):
    self.__init__()
    self.board[0][7] = make_piece(BLACK_ROOK)
    self.board[1][7] = make_piece(BLACK_KNIGHT)
    self.board[2][7] = make_piece(BLACK_BISHOP)
    self.board[3][7] = make_piece(BLACK_QUEEN)
    self.board[4][7] = make_piece(BLACK_KING)
    self.board[5][7] = make_piece(BLACK_BISHOP)
    self.board[6][7] = make_piece(BLACK_KNIGHT)
    self.board[7][7] = make_piece(BLACK_ROOK)
    for x in xrange(8):
      self.board[x][6] = make_piece(BLACK_PAWN)

    self.board[0][0] = make_piece(WHITE_ROOK)
    self.board[1][0] = make_piece(WHITE_KNIGHT)
    self.board[2][0] = make_piece(WHITE_BISHOP)
    self.board[3][0] = make_piece(WHITE_QUEEN)
    self.board[4][0] = make_piece(WHITE_KING)
    self.board[5][0] = make_piece(WHITE_BISHOP)
    self.board[6][0] = make_piece(WHITE_KNIGHT)
    self.board[7][0] = make_piece(WHITE_ROOK)
    for x in xrange(8):
      self.board[x][1] = make_piece(WHITE_PAWN)
    
  
  def initialize_pawn_square(self):
    self.__init__()
    for rank in range(1,9):
      self.put_piece(WHITE_PAWN, Position('a' + str(rank)))
      self.put_piece(BLACK_PAWN, Position('h' + str(rank)))
    for file in range(2,8):
      self.put_piece(WHITE_PAWN, Position(chr(ord('a') - 1 + file) + str(8)))
      self.put_piece(BLACK_PAWN, Position(chr(ord('a') - 1 + file) + str(1)))
    
  def __str__(self):
    output = '  a b c d e f g h\n'
    
    for y in [7 - y_prime for y_prime in range(8)]:
      output += str(y+1) + ' '
      for x in xrange(8):
        item = self.board[x][y]
        if item:
          output += item
        else:
          output += '_'
        if x < 7:
          output += ' '
      if y > 0:
        output += '\n'
    return output
   
  def print_side(self, other):
    output = '  a b c d e f g h   a b c d e f g h\n'
    
    for y in [7 - y_prime for y_prime in range(8)]:
      output += str(y+1) + ' '
      for x in xrange(8):
        item = self.board[x][y]
        if item:
          output += item
        else:
          output += '_'
        if x < 7:
          output += ' '
      # space
      output += '   '
      # again
      for x in xrange(8):
        item = other.board[x][y]
        if item:
          output += item
        else:
          output += '_'
        if x < 7:
          output += ' '
      if y > 0:
        output += '\n'
    return output

def test_chessboard():
  def test_initialize_standard_board():
    b = Chessboard()
    b.initialize_standard_board()
    assert str(b) == '''  a b c d e f g h
8 r k b q w b k r
7 p p p p p p p p
6 _ _ _ _ _ _ _ _
5 _ _ _ _ _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 P P P P P P P P
1 R K B Q W B K R'''

  def test_opening_moves():
    b = Chessboard()
    b.initialize_standard_board()
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'a2a3, a2a4, b1c3, b1a3, b2b3, b2b4, c2c3, c2c4, d2d3, d2d4, e2e3, e2e4, f2f3, f2f4, g1h3, g1f3, g2g3, g2g4, h2h3, h2h4'.split(', ')])
    my_debug = 'test_opening_moves'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 r k b q w b k r
7 p p p p p p p p
6 _ _ _ _ _ _ _ _
5 _ _ _ _ _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 P P P P P P P P
1 R K B Q W B K R'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_opening_moves')

  def test1():
    b = Chessboard()
    b.initialize_standard_board()
    b.force_move(Move('b2b3'))
    b.force_move(Move('c2c4'))
    b.force_move(Move('d2d6'))
    b.force_move(Move('e2e7'))
    b.force_move(Move('e8a6'))
    b.force_move(Move('f2f8'))
    b.force_move(Move('g2g5'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'c4c5, b1a3, e7xd8, d6xc7, a2a3, a2a4, b1c3, b1d2, b3b4, c1b2, c1a3, c1d2, c1e3, c1f4, d1d2, d1d3, d1d4, d1d5, d1c2, d1e2, d1f3, d1g4, d1h5, e1f2, e1e2, e1d2, e7e8, f1e2, f1d3, f1g2, f1h3, g1h3, g1f3, g1e2, g5g6, h2h3, h2h4'.split(', ')])
    my_debug = 'test1'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 r k b q _ P k r
7 p p p p P p p p
6 w _ _ P _ _ _ _
5 _ _ _ _ _ _ P _
4 _ _ P _ _ _ _ _
3 _ P _ _ _ _ _ _
2 P _ _ _ _ _ _ P
1 R K B Q W B K R'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test1')

  def test_pawn_moves1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_PAWN, Position('d2'))
    b.put_piece(WHITE_PAWN, Position('e3'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd2d3, d2d4, e3e4'.split(', ')])
    debug_print(legal_set.difference(known_set), 'p', msg='test_pawn_moves1')
    debug_print(known_set.difference(legal_set), 'p', msg='test_pawn_moves1')
    debug_print(b, 'p', msg='test_pawn_moves1')
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ _ _ _ _ _ p
5 P _ _ _ _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ _ P _ _ p
2 P _ _ P _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_pawn_moves1')

  def test_rook_moves1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_ROOK, Position('d3'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd3xh3, d3xd1, d3d2, d3d4, d3d5, d3d6, d3d7, d3c3, d3b3, d3e3, d3f3, d3g3'.split(', ')])
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ _ _ _ _ _ p
5 P _ _ _ _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ R _ _ _ p
2 P _ _ _ _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_rook_moves1')
      
  def test_bishop_moves1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_BISHOP, Position('d3'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd3xb1, d3xh7, d3xf1, d3c2, d3c4, d3b5, d3e2, d3e4, d3f5, d3g6'.split(', ')])
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ _ _ _ _ _ p
5 P _ _ _ _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ B _ _ _ p
2 P _ _ _ _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_bishop_moves1')
      

  def test_knight_moves1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_KNIGHT, Position('d6'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd6f7, d6f5, d6b7, d6e4, d6c4, d6b5'.split(', ')])
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ _ K _ _ _ p
5 P _ _ _ _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ _ _ _ _ p
2 P _ _ _ _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_knight_moves1')

  def test_queen_moves1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_QUEEN, Position('d6'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd6xh2, d6xh6, d6xd1, d6d5, d6d4, d6d3, d6d2, d6d7, d6c6, d6b6, d6e6, d6f6, d6g6, d6c5, d6b4, d6c7, d6e5, d6f4, d6g3, d6e7'.split(', ')])
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ _ Q _ _ _ p
5 P _ _ _ _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ _ _ _ _ p
2 P _ _ _ _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_queen_moves1')

  def test_king_moves1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_KING, Position('d7'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd7c7, d7c6, d7d6, d7e6, d7e7'.split(', ')])
    my_debug = 'test_king_moves1'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ W _ _ _ p
6 P _ _ _ _ _ _ p
5 P _ _ _ _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ _ _ _ _ p
2 P _ _ _ _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_king_moves1')

  def test_pawn_capture1():
    b = Chessboard()
    b.initialize_blank()
    b.put_piece(WHITE_PAWN, Position('d5'))
    b.put_piece(BLACK_KNIGHT, Position('e6'))
    b.put_piece(BLACK_KNIGHT, Position('d6'))
    b.put_piece(BLACK_KNIGHT, Position('c6'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd5xc6, d5xe6'.split(', ')])
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 _ _ _ _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ _ k k k _ _ _
5 _ _ _ P _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 _ _ _ _ _ _ _ _
1 _ _ _ _ _ _ _ _'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_pawn_capture1')

  def test_rook_capture1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_ROOK, Position('d5'))
    b.put_piece(BLACK_KNIGHT, Position('e6'))
    b.put_piece(BLACK_KNIGHT, Position('d6'))
    b.put_piece(BLACK_KNIGHT, Position('c6'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd5d4, d5d3, d5d2, d5xd1, d5xd6, d5c5, d5b5, d5e5, d5f5, d5g5, d5xh5'.split(', ')])
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ k k k _ _ p
5 P _ _ R _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ _ _ _ _ p
2 P _ _ _ _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_rook_capture1')

  def test_knight_capture1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_KNIGHT, Position('d6'))
    b.put_piece(BLACK_PAWN, Position('f5'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd6f7, d6xf5, d6b7, d6e4, d6c4, d6b5'.split(', ')])
    my_debug = 'test_knight_capture1'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ _ K _ _ _ p
5 P _ _ _ _ p _ p
4 P _ _ _ _ _ _ p
3 P _ _ _ _ _ _ p
2 P _ _ _ _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_knight_moves1')

  def test_king_capture1():
    b = Chessboard()
    b.initialize_pawn_square()
    b.put_piece(WHITE_KING, Position('d2'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'd2xc1, d2xd1, d2xe1, d2e3, d2e2, d2c3, d2d3, d2c2'.split(', ')])
    debug_print(legal_set, 'test_king_capture1')
    debug_print(legal_set.difference(known_set), 'test_king_capture1')
    debug_print(known_set.difference(legal_set), 'test_king_capture1')
    debug_print(b, 'test_king_capture1')
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set)
    assert str(b) == '''  a b c d e f g h
8 P P P P P P P p
7 P _ _ _ _ _ _ p
6 P _ _ _ _ _ _ p
5 P _ _ _ _ _ _ p
4 P _ _ _ _ _ _ p
3 P _ _ _ _ _ _ p
2 P _ _ W _ _ _ p
1 P p p p p p p p'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), 'test_captures', msg='test_king_capture1')

  def test_four_move_checkmate():
    moves = [Move(m) for m in '''e2e4
e7e5
f1c4
b8c6
d1f3
c6b4
f3xf7'''.split('\n')]
    b = Chessboard()
    b.initialize_standard_board()  
    for move in moves:
      b.force_move(move)
    if debug_on('test_four_move_checkmate'):
      print 'debug state true'
      print 'Black moves', b.get_legal_moves(TEAM_BLACK)
      DEBUG_STATE['test_four_move_checkmate'] = True
      print 'test_four_move_checkmate\n', b
      print b.get_positions_of_kings_in_check()
      del DEBUG_STATE['test_four_move_checkmate']
      print 'debug state false'
  
  def test_castle_king1():
    b = Chessboard()
    b.initialize_blank()  
    b.put_piece(make_piece(WHITE_KING), Position('e1'))
    b.put_piece(make_piece(WHITE_ROOK), Position('h1'))
    b.put_piece(make_piece(WHITE_PAWN), Position('h2'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'e1f1, e1f2, h1g1, e1e2, e1d2, h1f1, e1d1, h2h4, h2h3, e1g1'.split(', ') if description])
    my_debug = 'test_castle_king1'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 _ _ _ _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ _ _ _ _ _ _ _
5 _ _ _ _ _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 _ _ _ _ _ _ _ P
1 _ _ _ _ W _ _ R'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), my_debug, msg=my_debug)
    
  def test_castle_king2():
    b = Chessboard()
    b.initialize_blank()  
    b.put_piece(make_piece(WHITE_KING), Position('e1'))
    b.put_piece(make_piece(WHITE_ROOK), Position('h1'))
    b.put_piece(make_piece(WHITE_PAWN), Position('h2'))
    b.put_piece(make_piece(BLACK_ROOK), Position('f8'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'h1g1, e1e2, e1d2, h1f1, e1d1, h2h4, h2h3'.split(', ') if description])
    my_debug = 'test_castle_king2'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 _ _ _ _ _ r _ _
7 _ _ _ _ _ _ _ _
6 _ _ _ _ _ _ _ _
5 _ _ _ _ _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 _ _ _ _ _ _ _ P
1 _ _ _ _ W _ _ R'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), my_debug, msg=my_debug)

  def test_castle_queen1():
    b = Chessboard()
    b.initialize_blank()  
    b.put_piece(make_piece(WHITE_KING), Position('e1'))
    b.put_piece(make_piece(WHITE_ROOK), Position('a1'))
    b.put_piece(make_piece(WHITE_PAWN), Position('a2'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'a2a3, a1d1, a2a4, a1b1, a1c1, e1c1, e1f1, e1f2, e1e2, e1d2, e1d1'.split(', ') if description])
    my_debug = 'test_castle_queen1'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 _ _ _ _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ _ _ _ _ _ _ _
5 _ _ _ _ _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 P _ _ _ _ _ _ _
1 R _ _ _ W _ _ _'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), my_debug, msg=my_debug)

  def test_castle_queen2():
    b = Chessboard()
    b.initialize_blank()  
    b.put_piece(make_piece(WHITE_KING), Position('e1'))
    b.put_piece(make_piece(WHITE_ROOK), Position('a1'))
    b.put_piece(make_piece(WHITE_PAWN), Position('a2'))
    b.put_piece(make_piece(BLACK_ROOK), Position('b8'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'a2a3, a1d1, a2a4, a1b1, a1c1, e1c1, e1f1, e1f2, e1e2, e1d2, e1d1'.split(', ') if description])
    my_debug = 'test_castle_queen2'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 _ r _ _ _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ _ _ _ _ _ _ _
5 _ _ _ _ _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 P _ _ _ _ _ _ _
1 R _ _ _ W _ _ _'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), my_debug, msg=my_debug)

  def test_castle_queen3():
    b = Chessboard()
    b.initialize_blank()  
    b.put_piece(make_piece(WHITE_KING), Position('e1'))
    b.put_piece(make_piece(WHITE_ROOK), Position('a1'))
    b.put_piece(make_piece(WHITE_PAWN), Position('a2'))
    b.put_piece(make_piece(BLACK_ROOK), Position('d8'))
    legal_moves = b.get_legal_moves(TEAM_WHITE)
    legal_set = set(legal_moves)
    known_set = set([Move(description) for description in 'a2a3, a1d1, a2a4, a1b1, a1c1, e1f1, e1f2, e1e2'.split(', ') if description])
    my_debug = 'test_castle_queen3'
    debug_print(legal_set, my_debug)
    debug_print(legal_set.difference(known_set), my_debug)
    debug_print(known_set.difference(legal_set), my_debug)
    debug_print(b, my_debug)
    assert legal_set.issubset(known_set) and legal_set.issuperset(known_set), my_debug
    assert str(b) == '''  a b c d e f g h
8 _ _ _ r _ _ _ _
7 _ _ _ _ _ _ _ _
6 _ _ _ _ _ _ _ _
5 _ _ _ _ _ _ _ _
4 _ _ _ _ _ _ _ _
3 _ _ _ _ _ _ _ _
2 P _ _ _ _ _ _ _
1 R _ _ _ W _ _ _'''
    orig = b.copy()
    mark_moves_as_captures(b, legal_set)
    debug_print(b.print_side(orig), my_debug, msg=my_debug)

  test_initialize_standard_board()
  test_opening_moves()
  
  test1()
  test_pawn_moves1()
  test_rook_moves1()
  test_knight_moves1()
  test_bishop_moves1()
  test_queen_moves1()
  test_king_moves1()
  test_pawn_capture1()
  test_rook_capture1()
  test_knight_capture1()
  test_king_capture1()
  test_four_move_checkmate()
  test_castle_king1()
  test_castle_king2()
  test_castle_queen1()
  test_castle_queen2()
  test_castle_queen3()
  
def debug_print(item, flag, msg=''):
  if flag in DEBUGGING_FLAGS:
    if msg:
      print msg, ' '
    print item

def debug_on(flag):
  return flag in DEBUGGING_FLAGS

if __name__ == '__main__':
  main()
  
